package logic

import (
	rediscache "ahutoj/web/cache/redis"
	"ahutoj/web/dao"
	mysqldao "ahutoj/web/dao/mysqlDao"
	"ahutoj/web/io/constanct"
	"ahutoj/web/io/request"
	"ahutoj/web/io/response"
	"ahutoj/web/middlewares"
	"ahutoj/web/models"
	"ahutoj/web/utils"
	"fmt"
	"time"

	"github.com/gin-gonic/gin"
)

func AddSubmit(ctx *gin.Context, req *request.AddSubmitReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	// 提交代码
	submit := dao.Submit{
		PID:           req.PID,
		CID:           req.CID,
		LID:           req.LID,
		UID:           req.UID,
		Source:        req.Source,
		Lang:          req.Lang,
		Result:        constanct.OJ_PENDING,
		SubmitTime:    time.Now().UnixMilli(),
		IsOriginJudge: false,
		OriginPID:     "",
	}
	if models.EqualLastSource(ctx, req.UID, req.PID,int64(req.Lang) ,submit.Source) {
		return response.CreateResponseStr(constanct.SUBMIT_ADD_DUPLICATECODE, "禁止频繁重复提交代码", response.WARNING), nil
	}
	problem, err := models.GetProblemByPID(ctx, req.PID)
	if err != nil {
		logger.Errorf("call GetProblemByPID failed,pid=%v, err=%s", req.PID, err.Error())
		return response.CreateResponse(constanct.SUBMIT_ADD_FAILEDCode), err
	}
	if problem.Origin != -1 {
		submit.OJPlatform = problem.Origin
		submit.IsOriginJudge = true
		submit.OriginPID = problem.OriginPID
	}else if req.OnlineJudging {
		submit.OJPlatform = 0
		dataDir:=utils.GetConfInstance().DataPath+"/"+submit.UID
		err = utils.SaveFile(dataDir,fmt.Sprintf("%v.in",time.Now().UnixNano()),[]byte(req.Input))
		if err!=nil{
			return response.CreateResponse(constanct.SUBMIT_ADD_FAILEDCode), err
		}
		err = models.CommitRabitMQ(ctx, submit)
		if err != nil {
			return response.CreateResponse(constanct.SUBMIT_ADD_FAILEDCode), nil
		}
		return response.CreateResponse(constanct.SuccessCode), nil
	} else {
		submit.OJPlatform=-1
	}
	if req.CID > 0 {
		contest, err := models.GetContestFromDB(ctx, req.CID)
		if err != nil {
			logger.Errorf("call GetContestFromDB failed,pid=%v, err=%s", req.PID, err.Error())
			return response.CreateResponse(constanct.SUBMIT_ADD_FAILEDCode), err
		}
		// 比赛未开始 不能提交代码
		if contest.Begin_time > time.Now().UnixMilli() {
			return response.CreateResponse(constanct.SUBMIT_ADD_CONTESTNOTSTART_CODE), nil
		}
	}
	/*提交代码*/
	err = models.CreateSubmit(ctx, submit)
	if err != nil {
		logger.Errorf("call CreateSubmit failed, submit=%v, err=%s", submit, err.Error())
		return response.CreateResponse(constanct.SUBMIT_ADD_FAILEDCode), err
	}
	if rediscache.CountGetByRedis(ctx,rediscache.SubmitCountKey()) != 0 {
		rediscache.CountGetAddRedis(ctx,rediscache.SubmitCountKey())
	}
	submit, err = models.FindLastSIDByUID(ctx, submit.UID)
	if err != nil {
		logger.Errorf("call FindLastSIDByUID failed, UID=%v, err=%s", submit.UID, err.Error())
		return response.CreateResponse(constanct.SUBMIT_ADD_FAILEDCode), err
	}

	err = models.CommitRabitMQ(ctx, submit)
	if err != nil {
		return response.CreateResponse(constanct.SUBMIT_ADD_FAILEDCode), nil
	}
	return response.AddSubmitResp{
		Response: response.CreateResponse(constanct.SuccessCode),
		SID:      submit.SID,
	}, nil
}
func RejudgeSubmitReqToSubmit(req *request.RejudgeSubmitReq) (submit dao.Submit,submitTime int64) {
	if req.SID != nil {
		submit.SID = *req.SID
	}
	if req.CID != nil {
		submit.CID = *req.CID
	}
	if req.LID != nil {
		submit.LID = *req.LID
	}
	if req.PID != nil {
		submit.PID = *req.PID
	}
	if req.UID != nil {
		submit.UID = *req.UID
	}
	if req.Lang!=nil{
		submit.Lang = *req.Lang
	}
	if req.SubmitTime != nil {
		submitTime = *req.SubmitTime
	}else{
		submitTime = 0
	}
	return
}
func RejudgeSubmit(ctx *gin.Context, req *request.RejudgeSubmitReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	submit,submitTime := RejudgeSubmitReqToSubmit(req)
	// err := models.RejudgeSubmit(ctx, submit)
	// if err != nil {
	// 	return response.CreateResponse(constanct.SUBMIT_REJUDG_FAILEDCode), err
	// }
	submits, err := models.GetSubmitList(ctx, submit,submitTime, 0, 10000)
	if err != nil {
		logger.Errorf("call GetSubmitList failed,req=%+v,err=%s", utils.Sdump(req), err.Error())
		return nil, err
	}
	go func(){
		for _, s := range submits {
			err = models.CommitRabitMQ(ctx, s)
			if err!=nil{
				logger.Errorf("RejudgeSubmit,submit=%v,err=%s", s, err.Error())
			}
			time.Sleep(time.Second)
		}
	}()
	return response.CreateResponse(constanct.SuccessCode), err
}

func RejudgeSubmitCount(ctx *gin.Context, req *request.RejudgeSubmitReq) (interface{}, error){
	logger := utils.GetLogInstance()
	submit,submitTime := RejudgeSubmitReqToSubmit(req)
	// err := models.RejudgeSubmit(ctx, submit)
	// if err != nil {
	// 	return response.CreateResponse(constanct.SUBMIT_REJUDG_FAILEDCode), err
	// }
	submits, err := models.GetSubmitList(ctx, submit,submitTime, 0, 10000)
	if err != nil {
		logger.Errorf("call GetSubmitList failed,req=%+v,err=%s", utils.Sdump(req), err.Error())
		return nil, err
	}
	return response.RejudgeSubmitCountResp{
		Response: response.CreateResponse(constanct.SuccessCode),
		Count:    len(submits),
	},nil
}
func GetSubmits(ctx *gin.Context, req *request.SubmitListReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	resp := response.SubmitListResp{}
	submit := dao.Submit{}
	if req.CID != nil {
		submit.CID = *req.CID
	}
	if req.LID != nil {
		submit.LID = *req.LID
	}
	if req.PID != nil {
		submit.PID = *req.PID
	}
	if req.UID != nil {
		submit.UID = *req.UID
	}
	if req.Lang != nil {
		submit.Lang = *req.Lang
	}
	if req.Result != nil {
		submit.Result = *req.Result
	}
	offset, limit := utils.GetPageInfo(req.Page, req.Limit)
	submits, err := models.GetSubmitList(ctx, submit, 0,offset, limit)
	if err != nil {
		logger.Errorf("call SelectSubmitList failed,req=%+v,err=%s", utils.Sdump(req), err.Error())
		return response.CreateResponse(constanct.SUBMIT_LIST_FAILEDCode), err
	}
	if req.CID ==nil&&req.PID ==nil&&req.UID ==nil&&req.Lang ==nil&&req.Result ==nil&&req.LID==nil{
		resp.Count, err = rediscache.GetSubmitCount(ctx)
	}else{
		resp.Count, err = models.GetSubmitListCount(ctx, submit)
	}
	if err != nil {
		return response.CreateResponse(constanct.SUBMIT_LIST_FAILEDCode), err
	}
	resp.Response = response.CreateResponse(constanct.SuccessCode)
	resp.Data = make([]response.SubmitLIstItem, len(submits))
	for i, temp := range submits {
		resp.Data[i] = response.SubmitLIstItem{
			SID:        temp.SID,
			UID:        temp.UID,
			PID:        temp.PID,
			Lang:       temp.Lang,
			PassSample:  temp.PassSample,
			SampleNumber: temp.SampleNmuber,
			Result:     temp.Result,
			UseTime:    temp.Usetime,
			UseMemory:  temp.UseMemory,
			SubmitTime: temp.SubmitTime,
		}
	}
	return resp, nil
}

func GetSubmit(ctx *gin.Context, req *request.GetSubmitReq) (interface{}, error) {
	logger := utils.GetLogInstance()
	submit, err := mysqldao.SelectSubmitBySID(ctx, req.SID)
	if !middlewares.CheckUserHasPermission(ctx, constanct.SourceBorwser) &&
		submit.UID != middlewares.GetUid(ctx) {
		return response.CreateResponse(constanct.AUTH_Token_URLVerifyCode), err
	}
	if err != nil {
		logger.Errorf("Call SelectSubmitBySID failed, SID=%v, err=%s", req.SID, err.Error())
		return response.CreateResponse(constanct.SUBMIT_GET_FAILEDCode), err
	}
	var errInfo string
	if submit.Result == constanct.OJ_CE ||submit.Result==constanct.OJ_RE {
		errInfo = models.FindSubmitErrInfo(ctx, req.SID) //
	}
	return response.GetSubmitResp{
		Response:     response.CreateResponse(constanct.SuccessCode),
		SID:          submit.SID,
		UID:          submit.UID,
		PID:          submit.PID,
		Source:       submit.Source,
		Lang:         submit.Lang,
		Result:       submit.Result, //
		PassSample:   submit.PassSample,
		SampleNumber: submit.SampleNmuber,
		UseTime:      submit.Usetime,
		UseMemory:    submit.UseMemory,
		SubmitTime:   submit.SubmitTime,
		ErrInfo:       &errInfo,
	}, nil
}
